package clock.socoolby.com.clock.todo;

import android.app.Activity;
import android.content.Context;
import android.util.Log;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicBoolean;

import clock.socoolby.com.clock.Constants;
import clock.socoolby.com.clock.event.ClockEvent;
import clock.socoolby.com.clock.event.EventManger;
import clock.socoolby.com.clock.net.NetworkManager;
import clock.socoolby.com.clock.net.auth.AuthCallback;
import clock.socoolby.com.clock.net.base.I_ResponseState;
import clock.socoolby.com.clock.net.listener.StateAbleRequestListener;
import clock.socoolby.com.clock.todo.config.TodoSyncConfig;
import clock.socoolby.com.clock.todo.microsoft.MicrosoftTodoSyncServiceImpl;
import clock.socoolby.com.clock.todo.microsoft.bean.todo.TodoEntity;
import clock.socoolby.com.clock.todo.microsoft.bean.todo.TodoStatusEnum;
import clock.socoolby.com.clock.todo.microsoft.utils.TypeUtils;
import clock.socoolby.com.clock.utils.FileUtils;
import clock.socoolby.com.clock.utils.TimeUtils;

public class TodoSyncServiceManager {
    public static final String TAG=TodoSyncServiceManager.class.getCanonicalName();

    Map<String,I_TodoSyncService> syncServicesMap;

    List<TodoEntity> todoEntities=new ArrayList<>();

    TodoSyncConfig syncConfig;

    TodoSyncPerferenceModel perferenceModel;

    AtomicBoolean running=new AtomicBoolean(false);

    Date lastSyncTime;

    List<TodoEntity> todayTodoEntities;

    boolean mustReflush=false;

    //当天第一个要提醒Todo的小时数
    int nearAlterHour=999;

    Context applicationContext;

    boolean inited=false;

    public TodoSyncServiceManager(Context applicationContext){
        syncServicesMap=new HashMap<>();
        perferenceModel=new TodoSyncPerferenceModel();
        this.applicationContext=applicationContext;

        //loadSyncConfig();

        MicrosoftTodoSyncServiceImpl microsoftTodoSyncServices=new MicrosoftTodoSyncServiceImpl();

        syncServicesMap.put(microsoftTodoSyncServices.getServiceName(),microsoftTodoSyncServices);
    }

    public void start(){
        if(inited)
            return;
        for (I_TodoSyncService todoSyncService : syncServicesMap.values())
            todoSyncService.start(applicationContext, NetworkManager.getInstance());
        inited=true;
    }

    public void stop(){
        inited=false;
    }

    public void singIn(String serviceName, Activity activity, AuthCallback authCallback){
        if(!inited){
            authCallback.onCancel();
            return;
        }
        I_TodoSyncService syncService=syncServicesMap.get(serviceName);
        if(!syncService.isSignIn())
            syncService.signIn(activity,authCallback);
        else
            authCallback.onSuccess();
    }

    public void startSyncAllEntitys(){
        if(!inited||running.get())
            return;
        Runnable call=new Runnable(){
            @Override
            public void run() {
                    running.set(true);
                    StateAbleRequestListener<List<TodoEntity>, I_ResponseState> requestListener;
                    /*if(lastSyncTime!=null) {


                    }else {*/
                        todoEntities.clear();
                        for (I_TodoSyncService todoSyncService : syncServicesMap.values()) {
                            if (todoSyncService.isSignIn()) {
                                requestListener = new StateAbleRequestListener<List<TodoEntity>, I_ResponseState>() {
                                    @Override
                                    public void onResponse(List<TodoEntity> response, I_ResponseState state) {
                                        if (response != null) {
                                            todoEntities.addAll(response);
                                        }
                                        if (state.hasNext())
                                            todoSyncService.next(state, this);
                                        else {
                                            EventManger.post(ClockEvent.buildTodoSyncSuccess(todoSyncService.getServiceName()));
                                            mustReflush = true;
                                        }
                                    }

                                    @Override
                                    public void onRequestFailed(int error, String errorMessage) {
                                        timber.log.Timber.d(errorMessage);
                                    }
                                };
                                todoSyncService.list(requestListener);

                            }
                        }
                    //}
                running.set(false);
                lastSyncTime=new Date();
            }
        } ;
        Thread thread=new Thread(call);
        thread.start();
    }


    public void completeTodoEntity(TodoEntity todo) {
        syncServicesMap.get(MicrosoftTodoSyncServiceImpl.NAME).completeTodoEntity(todo.getId(), new StateAbleRequestListener<List<TodoEntity>, I_ResponseState>() {
            @Override
            public void onResponse(List<TodoEntity> response, I_ResponseState state) {
                if(response!=null) {
                    todoEntities.remove(todo);
                    todoEntities.addAll(response);
                }
            }

            @Override
            public void onRequestFailed(int error, String errorMessage) {

            }
        });
    }

    public TodoEntity getAlterTodoEntityByDate(Date toCheckDate){
        if(mustReflush)
            syncEndAlterCheck();
        if(nearAlterHour>toCheckDate.getHours()||todayTodoEntities.isEmpty())
            return null;
        TodoEntity first=todayTodoEntities.get(0);
        if(isTimeBefore(first.getReminderdatetime().getDateTime(),toCheckDate)){
            todayTodoEntities.remove(first);
            resetNearAlterHour();
            return first;
        }
        return null;
    }

    public void delayTodoEntity(TodoEntity newTodoEntity){
        if(isTodayEntity(newTodoEntity)) {
            todayTodoEntities.add(newTodoEntity);
            sortTodayTodoEntities();
            resetNearAlterHour();
        }
    }

    private void loadSyncConfig(){
        if (!FileUtils.isExistsFile(Constants.TODO_SYNC_PERFERENCE_FILE)) {
            saveSyncConfig();
        }else {
            perferenceModel.read();
            syncConfig = perferenceModel.getTodoSyncConfig();
        }
    }

    private void saveSyncConfig(){
        perferenceModel.setTodoSyncConfig(syncConfig);
        perferenceModel.save();
    }

    public TodoSyncPerferenceModel getPerferenceModel() {
        return perferenceModel;
    }

    public List<TodoEntity> getTodoEntities() {
        return todoEntities;
    }

    public void syncEndAlterCheck(){
        todayTodoEntities=new ArrayList<>();
        for(TodoEntity entity:todoEntities){
            if(isTodayEntity(entity)) {
                todayTodoEntities.add(entity);
            }
        }

        sortTodayTodoEntities();

        resetNearAlterHour();
    }

    private void sortTodayTodoEntities(){
        Collections.sort(todayTodoEntities, new Comparator<TodoEntity>() {
            @Override
            public int compare(TodoEntity o1, TodoEntity o2) {
                Calendar calendar=Calendar.getInstance();
                calendar.setTime(o1.getReminderdatetime().getDateTime());
                Calendar calendar2=Calendar.getInstance();
                calendar2.setTime(o2.getReminderdatetime().getDateTime());
                return calendar.compareTo(calendar2);
            }
        });
    }

    private void resetNearAlterHour(){
        nearAlterHour=999;
        if(todayTodoEntities.size()>0)
            nearAlterHour=todayTodoEntities.get(0).getReminderdatetime().getDateTime().getHours();
    }


    private boolean isTodayEntity(TodoEntity todoEntity){
        boolean ret=todoEntity.getStatus()!=null&&todoEntity.getStatus()!= TodoStatusEnum.completed;
        if(ret)
           ret=ret&&todoEntity.getReminderdatetime()!=null&&isToday(todoEntity.getReminderdatetime().getDateTime());
        return ret;
    }

    private boolean isToday(Date toCheckday){
        if(toCheckday==null)
            return false;
        return TimeUtils.isToday(toCheckday);
    }

    private boolean isSameDay(Date base,Date toCheckday){
        if(toCheckday==null)
            return false;
        //timber.log.Timber.d("isSameDay from:"+ TypeUtils.dayFormat(base)+"\t to:"+TypeUtils.dayFormat(toCheckday));
        return TimeUtils.isSameDay(base,toCheckday);
    }

    private boolean isSameTime(Date base,Date toCheckday){
        return TimeUtils.isSameTime(base,toCheckday);
    }

    public static boolean isTimeBefore(Date base,Date toCheckday){
        return TimeUtils.isTimeBefore(base,toCheckday);
    }

    public List<TodoEntity> getTodayTodoEntities() {
        return todayTodoEntities;
    }

    public List<TodoEntity> getTodoEntities(int year, int month, int day) {
        List<TodoEntity> retEntities=new ArrayList<>();
        Calendar calendar=Calendar.getInstance();
        calendar.set(year,month,day);
        for(TodoEntity entity:todoEntities){
            if(isSameDay(entity.getCreateddatetime(),calendar.getTime())) {
                retEntities.add(entity);
            }
        }
        return retEntities;
    }

    public boolean isServiceAble() {
        return inited;
    }

}
